
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>主从架构实现原理 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>主从架构实现原理 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">RocketMQ的同步复制和异步复制模式在工作流程与特性上有何核心差异？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">核心差异在于何时向生产者返回成功响应。在同步复制模式下，Master节点必须将消息成功复制到Slave并收到确认后，才向生产者返回成功响应，这保证了数据零丢失，但性能较低。而在异步复制模式下，Master将消息写入本地CommitLog后就立即返回成功响应，之后再异步地将消息复制到Slave，这种方式性能较高，但在Master宕机时可能丢失尚未同步的数据。</div>
          </div>
          <div class="card-source">来源: 「2. 同步复制与异步复制」</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">相较于传统的主从模式，Dledger模式在处理写故障转移时有何显著优势？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Dledger模式的显著优势是支持自动故障转移。它基于Raft协议，当Leader（主节点）发生故障时，集群能够自动选举出新的Leader来接管写服务，整个过程无需人工干预，恢复时间短。而传统主从模式下的写故障转移需要管理员手动操作，将一个Slave提升为Master，过程复杂且耗时。</div>
          </div>
          <div class="card-source">来源: 「3.2 Dledger模式（自动故障转移）」</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">在RocketMQ中，如何通过配置将一个Master节点和一个Slave节点关联成主从关系？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">主从节点通过两个关键配置参数进行关联：1. 设置相同的`brokerName`。2. 设置不同的`brokerId`，其中Master节点的`brokerId`必须为0，而Slave节点的`brokerId`必须是大于0的整数。</div>
          </div>
          <div class="card-source">来源: 「3. 主从节点关联配置」</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">在RocketMQ的主从复制过程中，Slave节点是如何确定应该从Master的哪个位置开始同步数据的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">当Slave启动并连接到Master后，它会向Master发送自己当前的最大物理偏移量（maxPhyOffset）。Master根据接收到的这个偏移量，就能确定从CommitLog的哪个位置开始向该Slave传输数据，从而实现增量同步。</div>
          </div>
          <div class="card-source">来源: 「1.2 复制流程」</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">RocketMQ的Slave节点是如何同步Master节点的索引文件（如ConsumeQueue和IndexFile）的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">RocketMQ并不会直接在主从之间同步索引文件。主从复制的核心是同步CommitLog文件。Slave节点在接收并写入CommitLog数据后，其内部的ReputMessageService服务会解析CommitLog，并根据解析结果在本地重建ConsumeQueue和IndexFile等索引文件。</div>
          </div>
          <div class="card-source">来源: 「3.2 索引文件同步」</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">当Master节点不可用时，RocketMQ的消费者是如何实现读故障转移以继续消费消息的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">当消费者向Master请求消息失败时，它会向NameServer查询该Broker组的Slave信息。获取到Slave地址后，消费者会自动切换到Slave节点继续读取消息。要启用此功能，Broker的配置中需要设置`slaveReadEnable=true`。</div>
          </div>
          <div class="card-source">来源: 「2.1 消费者故障转移」</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">根据文档中的最佳实践，针对“核心业务生产环境”，推荐使用哪两种部署模式？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">针对核心业务生产环境，文档推荐使用“多Master多Slave同步复制模式”或“Dledger模式”。这两种模式都能提供最高级别的数据可靠性，确保数据强一致性或零丢失。</div>
          </div>
          <div class="card-source">来源: 「1.2 部署模式选择」</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">在RocketMQ的配置文件中，`brokerRole`参数的三个主要配置值及其含义分别是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`brokerRole`参数用于定义Broker的角色，主要有三个值：<br>1. `SYNC_MASTER`：代表同步复制模式下的Master节点。<br>2. `ASYNC_MASTER`：代表异步复制模式下的Master节点。<br>3. `SLAVE`：代表Slave节点。</div>
          </div>
          <div class="card-source">来源: 「2. 主从节点角色配置」</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">Dledger模式是如何在发生故障转移后依然能保证数据强一致性的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Dledger模式基于Raft协议，通过两个核心机制保证强一致性：1. 消息只有在被成功复制到集群中的多数节点后，才会被确认为提交成功。2. 当需要选举新的Leader时，协议确保只有拥有最新、最完整数据的节点才有资格当选。这保证了任何已确认的消息都不会丢失。</div>
          </div>
          <div class="card-source">来源: 「4.3 Dledger模式」</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
